package com.dji.activationDemo.websocket;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.text.TextUtils;

import com.dji.activationDemo.Constant;
import com.dji.activationDemo.messaging.MessageProcessing;
import com.dji.activationDemo.uitls.WriteLog;
import com.neovisionaries.ws.client.WebSocket;
import com.neovisionaries.ws.client.WebSocketAdapter;
import com.neovisionaries.ws.client.WebSocketException;
import com.neovisionaries.ws.client.WebSocketFactory;
import com.neovisionaries.ws.client.WebSocketFrame;
import com.neovisionaries.ws.client.WebSocketListener;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import dji.log.third.Logger;

public class WsManager {
    private static WsManager mInstance;
    private final String TAG = this.getClass().getSimpleName();


    /**
     * WebSocket config
     */
    private static final int FRAME_QUEUE_SIZE = 5;
    private static final int CONNECT_TIMEOUT = 5000;
    private static final String DEF_URL = Constant.DEF_URL;
    private String url;

    private WsStatus mStatus;
    public static WebSocket ws;
    private WsListener mListener;
    private long heartTime = System.currentTimeMillis();

    private boolean onOff = true;

    MessageProcessing messageProcessing = new MessageProcessing();

    private WsManager() {
    }

    public static WsManager getInstance() {
        if (mInstance == null) {
            synchronized (WsManager.class) {
                if (mInstance == null) {
                    mInstance = new WsManager();
                }
            }
        }
        return mInstance;
    }

    public void init() {
        onOff = true;
        try {
            /**
             * configUrl其实是缓存在本地的连接地址
             * 这个缓存本地连接地址是app启动的时候通过http请求去服务端获取的,
             * 每次app启动的时候会拿当前时间与缓存时间比较,超过6小时就再次去服务端获取新的连接地址更新本地缓存
             */
            String configUrl = "";
            url = TextUtils.isEmpty(configUrl) ? DEF_URL : configUrl;
            ws = new WebSocketFactory().createSocket(url, CONNECT_TIMEOUT)
                    .setFrameQueueSize(FRAME_QUEUE_SIZE)//设置帧队列最大值为5
                    .setMissingCloseFrameAllowed(false)//设置不允许服务端关闭连接却未发送关闭帧
                    .addListener((WebSocketListener) (mListener = new WsListener()))//添加回调监听
                    .connectAsynchronously();//异步连接
            setStatus(WsStatus.CONNECTING);
            Constant.webSocketState = "正在连接";
            Logger.t(TAG).d("第一次连接");
            WriteLog.writeLog("连接一次webSocket");

        } catch (Exception e) {
//            e.printStackTrace();
            System.out.println(e.getMessage());
//            System.out.println("zl init:" + e.getMessage());
        }
    }


    /**
     * 继承默认的监听空实现WebSocketAdapter,重写我们需要的方法
     * onTextMessage 收到文字信息
     * onConnected 连接成功
     * onConnectError 连接失败
     * onDisconnected 连接关闭
     */
    class WsListener extends WebSocketAdapter {


        @Override
        public void onTextMessage(WebSocket websocket, String text) throws Exception {
            super.onTextMessage(websocket, text);
            heartTime = System.currentTimeMillis();
            System.out.println(text);
            if (text.equals("heart")) {
                WriteLog.writeLog("收到一次心跳");
                System.out.println("收到一次心跳");
                Constant.webSocketState = "连接成功";
                ws.sendText("heart*"+Constant.EQUIPMENT_ID+"*heartTime");
            } else {
                WriteLog.writeLog("收到指令:" + text);
                System.out.println("收到指令：" + text);
                messageProcessing.handleMesaage(text);
            }
        }


        @Override
        public void onConnected(WebSocket websocket, Map<String, List<String>> headers)
                throws Exception {
            super.onConnected(websocket, headers);
            Logger.t(TAG).d("连接成功");
            WriteLog.writeLog("连接成功");
            Constant.webSocketState = "连接成功";
            setStatus(WsStatus.CONNECT_SUCCESS);
            heartTime = System.currentTimeMillis();
            cancelReconnect();//连接成功的时候取消重连,初始化连接次数
            mHandler.post(mHeartCheck);
//            ws.sendText("and*发送消息测试");
        }


        @Override
        public void onConnectError(WebSocket websocket, WebSocketException exception)
                throws Exception {
            super.onConnectError(websocket, exception);
            WriteLog.writeLog("连接错误");
            Logger.t(TAG).d("连接错误");
            Constant.webSocketState = "连接错误";
            setStatus(WsStatus.CONNECT_FAIL);
            mHandler.removeCallbacks(mHeartCheck);
            reconnect();//连接错误的时候调用重连方法
        }


        @Override
        public void onDisconnected(WebSocket websocket, WebSocketFrame serverCloseFrame, WebSocketFrame clientCloseFrame, boolean closedByServer)
                throws Exception {
            super.onDisconnected(websocket, serverCloseFrame, clientCloseFrame, closedByServer);
            Logger.t(TAG).d("断开连接");
            WriteLog.writeLog("断开连接");
            Constant.webSocketState = "断开连接";
            setStatus(WsStatus.CONNECT_FAIL);
            mHandler.removeCallbacks(mHeartCheck);
            if (onOff)
                reconnect();//连接断开的时候调用重连方法
        }
    }

    private void setStatus(WsStatus status) {
        this.mStatus = status;
    }

    private WsStatus getStatus() {
        return mStatus;
    }

    public void disconnect() {
        if (ws != null)
            onOff = false;
        System.out.println("websocket关闭");
        ws.disconnect();
    }

    public enum WsStatus {
        CONNECT_SUCCESS,//连接成功
        CONNECT_FAIL,//连接失败
        CONNECTING;//正在连接
    }

    private Handler mHandler = new Handler();

    private int reconnectCount = 0;//重连次数
    private long minInterval = 3000;//重连最小时间间隔
    private long maxInterval = 60000;//重连最大时间间隔

    public void reconnect() {
        //这里其实应该还有个用户是否登录了的判断 因为当连接成功后我们需要发送用户信息到服务端进行校验
        //由于我们这里是个demo所以省略了
        if (ws != null &&
                !ws.isOpen() &&//当前连接断开了
                getStatus() != WsStatus.CONNECTING) {//不是正在重连状态

            reconnectCount++;
            setStatus(WsStatus.CONNECTING);
            Constant.webSocketState = "正在连接";

            long reconnectTime = minInterval;
//            if (reconnectCount > 3) {
//                url = DEF_URL;
//                long temp = minInterval * (reconnectCount - 2);
//                reconnectTime = temp > maxInterval ? maxInterval : temp;
//            }
            WriteLog.writeLog("准备开始第" + reconnectCount + "次重连。");
            Logger.t(TAG).d("准备开始第%d次重连,重连间隔%d -- url:%s", reconnectCount, reconnectTime, url);
            mHandler.postDelayed(mReconnectTask, reconnectTime);
        }
    }

    private Runnable mReconnectTask = new Runnable() {
        @Override
        public void run() {
            try {
                ws = new WebSocketFactory().createSocket(url, CONNECT_TIMEOUT)
                        .setFrameQueueSize(FRAME_QUEUE_SIZE)//设置帧队列最大值为5
                        .setMissingCloseFrameAllowed(false)//设置不允许服务端关闭连接却未发送关闭帧
                        .addListener(mListener = new WsListener())//添加回调监听
                        .connectAsynchronously();//异步连接
                setStatus(WsStatus.CONNECTING);
                Constant.webSocketState = "正在连接";
            } catch (Exception e) {
                //e.printStackTrace();
                System.out.println(e.getMessage());
            }
        }
    };

    private Runnable mHeartCheck = new Runnable() {
        @Override
        public void run() {
            if ((System.currentTimeMillis() - heartTime) > 12000) {
                Constant.webSocketState = "连接断开";
                WriteLog.writeLog("长时间没有收到心跳");
                System.out.println("长时间没有收到心跳");
                getInstance().disconnect();
                getInstance().init();
            }
            mHandler.postDelayed(mHeartCheck, 1000);
        }
    };

    private void cancelReconnect() {
        reconnectCount = 0;
        mHandler.removeCallbacks(mReconnectTask);
    }


}
